Merge status-key and layout changes
authorjustbur <justin@burkett.cc>
Sat, 11 Jul 2015 01:52:10 +0000 (21:52 -0400)
committerjustbur <justin@burkett.cc>
Sat, 11 Jul 2015 01:52:10 +0000 (21:52 -0400)
1  2 
which-key.el

diff --cc which-key.el
index c03954518006cef14e5852190c861a0c9c5e6351,7ef6328754475ad2aba53b68ac8e200dd7b3af87..d0703b6a975a0847e4cce77fd537c2d0b6b690b5
@@@ -676,47 -550,200 +550,220 @@@ non-nil regexp is used in the replaceme
  strings (including text properties), and pad with spaces so that
  all are a uniform length. Replacements are performed using the
  key and description replacement alists."
 -  (let ((max-key-width 0)) ;(max-desc-width 0)
 +  (let ((max-key-width 0)
-         (max-desc-width 0)
-         (sep-w-face (propertize which-key-separator 'face 'which-key-separator-face))
-         (sep-width (length which-key-separator))
-         after-replacements)
++        (sep-w-face (propertize which-key-separator 'face 'which-key-separator-face))) ;(max-desc-width 0)
      ;; first replace and apply faces
-     (setq after-replacements
-           (mapcar
-            (lambda (key-desc-cons)
-              (let* ((key (car key-desc-cons))
-                     (desc (cdr key-desc-cons))
-                     (keys (concat prefix-keys " " key))
-                     (key (which-key/maybe-replace key which-key-key-replacement-alist))
-                     (desc (which-key/maybe-replace desc which-key-description-replacement-alist))
-                     (desc (which-key/maybe-replace-key-based desc keys))
-                     (group (string-match-p "^group:" desc))
-                     (desc (if group (substring desc 6) desc))
-                     (prefix (string-match-p "^Prefix" desc))
-                     (desc (if (or prefix group) (concat "+" desc) desc))
-                     (desc-face (if (or prefix group)
-                                    'which-key-group-description-face
-                                  'which-key-command-description-face))
-                     (desc (which-key/truncate-description desc))
-                     (key-w-face (which-key/propertize-key key))
-                     (desc-w-face (propertize desc 'face desc-face))
-                     (key-width (length (substring-no-properties key-w-face)))
-                     (desc-width (length (substring-no-properties desc-w-face))))
-                (setq max-key-width (max key-width max-key-width))
-                (setq max-desc-width (max desc-width max-desc-width))
-                (cons key-w-face desc-w-face)))
-            unformatted))
-     ;; pad to max key-width and max desc-width
-     (cons
-      (mapcar (lambda (x)
-                (concat (s-pad-left max-key-width " " (car x))
-                        " " sep-w-face " "
-                        (s-pad-right max-desc-width " " (cdr x))
-                        " "))
-              after-replacements)
-      (+ 3 max-key-width sep-width max-desc-width ))))
+     (mapcar
+      (lambda (key-desc-cons)
+        (let* ((key (car key-desc-cons))
+               (desc (cdr key-desc-cons))
+               (keys (concat prefix-keys " " key))
+               (key (which-key/maybe-replace
+                     key which-key-key-replacement-alist))
+               (desc (which-key/maybe-replace
+                      desc which-key-description-replacement-alist))
+               (desc (which-key/maybe-replace-key-based desc keys))
+               (group (string-match-p "^group:" desc))
+               (desc (if group (substring desc 6) desc))
+               (prefix (string-match-p "^Prefix" desc))
+               (desc (if (or prefix group) (concat "+" desc) desc))
+               (desc-face (if (or prefix group)
+                              'which-key-group-description-face
+                            'which-key-command-description-face))
+               (desc (which-key/truncate-description desc))
+               (key-w-face (which-key/propertize-key key))
+               (desc-w-face (propertize desc 'face desc-face))
+               (key-width (length (substring-no-properties key-w-face))))
+          ;; (desc-width (length (substring-no-properties desc-w-face))))
+          (setq max-key-width (max key-width max-key-width))
+          ;; (setq max-desc-width (max desc-width max-desc-width))
 -         (cons key-w-face desc-w-face)))
++         (list key-w-face sep-w-face desc-w-face)))
+      unformatted)))
+ ;; pad to max key-width and max desc-width
+ (defun which-key/get-formatted-key-bindings (buffer key)
+   (let ((key-str-qt (regexp-quote (key-description key)))
+         key-match desc-match unformatted format-res
+         formatted column-width)
+     (with-temp-buffer
+       (describe-buffer-bindings buffer key)
+       (goto-char (point-max)) ; want to put last keys in first
+       (while (re-search-backward
+               (format "^%s \\([^ \t]+\\)[ \t]+\\(\\(?:[^ \t\n]+ ?\\)+\\)$"
+                       key-str-qt)
+               nil t)
+         (setq key-match (match-string 1)
+               desc-match (match-string 2))
+         (cl-pushnew (cons key-match desc-match) unformatted
+                     :test (lambda (x y) (string-equal (car x) (car y))))))
+     (which-key/format-and-replace unformatted (key-description key))))
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; Functions for laying out which-key buffer pages
 -(defun which-key/create-page-vertical (max-lines max-width prefix-width key-cns)
++(defsubst which-key//max-len (keys index)
++  (cl-reduce
++   (lambda (x y) (max x (if (eq (car y) 'status)
++                            0 (length (substring-no-properties (nth index y))))))
++   keys :initial-value 0))
++
++(defun which-key/create-page-vertical (keys max-lines max-width prefix-width)
+   "Format KEYS into string representing a single page of text.
+ N-COLUMNS is the number of text columns to use and MAX-LINES is
+ the maximum number of lines availabel in the target buffer."
 -  (let* ((n-keys (length key-cns))
++  (let* ((n-keys (length keys))
+          (avl-lines max-lines)
+          (avl-width (- (+ 1 max-width) prefix-width)); we get 1 back for not putting a space after the last column
 -         (rem-key-cns key-cns)
++         (rem-keys keys)
+          (n-col-lines (min avl-lines n-keys))
+          (act-n-lines n-col-lines) ; n-col-lines in first column
+          (all-columns (list
+                        (mapcar (lambda (i)
+                                  (if (> i 1) (s-repeat prefix-width " ") ""))
+                                      (number-sequence 1 n-col-lines))))
+          (act-width prefix-width)
 -         (sep-w-face (propertize which-key-separator
 -                                 'face 'which-key-separator-face))
 -         col-key-cns col-key-width col-desc-width col-width col-split done
 -         n-columns new-column page)
++         col-keys col-key-width col-desc-width col-width col-split done
++         n-columns new-column page col-sep-width prev-rem-keys)
+     (while (not done)
 -      (setq col-split      (-split-at n-col-lines rem-key-cns)
 -            col-key-cns    (car col-split)
 -            rem-key-cns    (cadr col-split)
 -            n-col-lines    (min avl-lines (length rem-key-cns))
 -            col-key-width  (cl-reduce (lambda (x y)
 -                                        (max x (length (substring-no-properties (car y)))))
 -                                      col-key-cns :initial-value 0)
 -            col-desc-width (cl-reduce (lambda (x y)
 -                                        (max x (length (substring-no-properties (cdr y)))))
 -                                      col-key-cns :initial-value 0)
 -            col-width      (+ 3 (length (substring-no-properties sep-w-face))
 -                              col-key-width col-desc-width)
++      (setq col-split      (-split-at n-col-lines rem-keys)
++            col-keys       (car col-split)
++            prev-rem-keys  rem-keys
++            rem-keys       (cadr col-split)
++            n-col-lines    (min avl-lines (length col-keys))
++            col-key-width  (which-key//max-len col-keys 0)
++            col-sep-width  (which-key//max-len col-keys 1)
++            col-desc-width (which-key//max-len col-keys 2)
++            col-width      (+ 3 col-key-width col-sep-width col-desc-width)
+             new-column     (mapcar
+                             (lambda (k)
 -                              (concat (s-repeat (- col-key-width (length (substring-no-properties (car k)))) " ")
 -                                      (car k) " " sep-w-face " " (cdr k)
 -                                      (s-repeat (- col-desc-width (length (substring-no-properties (cdr k)))) " ")))
 -                            col-key-cns))
++                              (if (eq (car k) 'status)
++                                  (concat (s-repeat (+ col-key-width col-sep-width) " ") "  " (cdr k))
++                                (concat (s-repeat (- col-key-width
++                                                     (length (substring-no-properties (nth 0 k)))) " ")
++                                        (nth 0 k) " " (nth 1 k) " " (nth 2 k)
++                                        (s-repeat (- col-desc-width
++                                                     (length (substring-no-properties (nth 2 k)))) " "))))
++                            col-keys))
+       (if (<= col-width avl-width)
+           (setq all-columns (push new-column all-columns)
+                 act-width   (+ act-width col-width)
 -                avl-width   (- avl-width col-width))
 -        (setq done t))
 -      (when (<= (length rem-key-cns) 0) (setq done t)))
++                avl-width   (- avl-width col-width)) 
++        (setq done t
++              rem-keys prev-rem-keys))
++      (when (<= (length rem-keys) 0) (setq done t)))
+     (setq all-columns (reverse all-columns)
+           n-columns (length all-columns))
+     (dotimes (i act-n-lines)
+       (dotimes (j n-columns)
+         (setq page (concat page (nth i (nth j all-columns))
+                            (if (not (= j (- n-columns 1))) " "
+                              (when (not (= i (- act-n-lines 1))) "\n"))))))
 -    (list page act-n-lines act-width rem-key-cns (- (length key-cns) (length rem-key-cns)))))
++    (list page act-n-lines act-width rem-keys (- n-keys (length rem-keys)))))
 -(defun which-key/create-page (vertical max-lines max-width prefix-width key-cns)
 -  (let* ((first-try (which-key/create-page-vertical max-lines max-width prefix-width key-cns))
++(defun which-key/create-page (keys max-lines max-width prefix-width vertical use-status-key page-n)
++  (let* ((n-keys (length keys))
++         (first-try (which-key/create-page-vertical keys max-lines max-width prefix-width))
+          (n-rem-keys (length (nth 3 first-try)))
++         (status-key-i (- n-keys n-rem-keys 1))
+          (next-try-lines max-lines)
 -         prev-try prev-n-rem-keys next-try found)
 -    (if (or vertical (> n-rem-keys 0) (= max-lines 1))
 -        first-try
 -      ;; do a simple search for now (TODO: Implement binary search)
 -      (while (not found)
 -        (setq prev-try next-try
 -              next-try-lines (- next-try-lines 1)
 -              next-try (which-key/create-page-vertical next-try-lines max-width prefix-width key-cns)
 -              n-rem-keys (length (nth 3 next-try))
 -              found (or (= next-try-lines 0) (> n-rem-keys 0))))
 -      prev-try)))
++         prev-try prev-n-rem-keys next-try found status-key)
++    (cond ((and (> n-rem-keys 0) use-status-key)
++           (setq status-key
++                 (cons 'status (propertize
++                                (format "Page %s (%s not shown)" page-n (1+ n-rem-keys))
++                                'face 'font-lock-comment-face)))
++           (which-key/create-page-vertical (-insert-at status-key-i status-key keys)
++                                           max-lines max-width prefix-width))
++          ((or (> n-rem-keys 0) (= 1 max-lines)) first-try)
++          ;; do a simple search for now (TODO: Implement binary search)
++          (t (while (not found)
++               (setq prev-try next-try
++                     next-try-lines (- next-try-lines 1)
++                     next-try (which-key/create-page-vertical
++                               keys next-try-lines max-width prefix-width)
++                     n-rem-keys (length (nth 3 next-try))
++                     found (or (= next-try-lines 0) (> n-rem-keys 0))))
++             prev-try))))
+ (defun which-key/populate-buffer (prefix-keys formatted-keys sel-win-width)
+   "Insert FORMATTED-STRINGS into which-key buffer, breaking after BUFFER-WIDTH."
+   (let* ((vertical (and (eq which-key-popup-type 'side-window)
+                         (member which-key-side-window-location '(left right))))
++         (use-status-key t)
+          (prefix-w-face (which-key/propertize-key prefix-keys))
+          (prefix-len (+ 2 (length (substring-no-properties prefix-w-face))))
+          (prefix-string (when which-key-show-prefix
+                           (if (eq which-key-show-prefix 'left)
+                               (concat prefix-w-face "  ")
+                             (concat prefix-w-face "-\n"))))
 -         (n-keys (length formatted-keys))
+          (max-dims (which-key/popup-max-dimensions sel-win-width))
 -         (max-height (when (car max-dims) (car max-dims)))
++         (max-lines (when (car max-dims) (car max-dims)))
+          (prefix-width (if (eq which-key-show-prefix 'left) prefix-len 0))
+          (avl-width (when (cdr max-dims) (- (cdr max-dims) prefix-width)))
+          (keys-rem formatted-keys)
++         (page-n 0)
+          keys-per-page pages first-page first-page-str page-res)
+     (while keys-rem
 -      (setq page-res (which-key/create-page vertical max-height avl-width prefix-width keys-rem)
++      (setq page-n (1+ page-n)
++            page-res (which-key/create-page keys-rem
++                                            max-lines avl-width prefix-width
++                                            vertical use-status-key page-n)
+             pages (push page-res pages)
+             keys-per-page (push (if (nth 4 page-res) (nth 4 page-res) 0) keys-per-page)
+             keys-rem (nth 3 page-res)))
+     ;; not doing anything with other pages for now
+     (setq keys-per-page (reverse keys-per-page)
+           pages (reverse pages)
+           first-page (car pages)
+           first-page-str (concat prefix-string (car first-page)))
 -    (if (or (<= n-keys 0) (<= (car keys-per-page) 0))
++    (if (or (= (length formatted-keys) 0) (<= (car keys-per-page) 0))
+         (progn
+           (message "which-key can't show keys: The settings and/or frame size are too restrictive.")
+           (cons 0 0))
+       ;; (when (> (length pages) 1) (setq first-page (concat first-page "...")))
+       (if (eq which-key-popup-type 'minibuffer)
+           (let (message-log-max) (message "%s" first-page-str))
+         (with-current-buffer which-key--buffer
+           (erase-buffer)
+           (insert first-page-str)
+           (goto-char (point-min))))
+       (cons (nth 1 first-page) (nth 2 first-page)))))
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;; Update
+ (defun which-key/update ()
+   "Fill which-key--buffer with key descriptions and reformat.
+ Finally, show the buffer."
+   (let ((prefix-keys (this-single-command-keys)))
+     ;; (when (> (length prefix-keys) 0)
+     ;;  (message "key: %s" (key-description prefix-keys)))
+     ;; (when (> (length prefix-keys) 0)
+     ;;  (message "key binding: %s" (key-binding prefix-keys)))
+     (when (and (> (length prefix-keys) 0)
+                (keymapp (key-binding prefix-keys)))
+       (let* ((buf (current-buffer))
+              ;; get formatted key bindings
+              (formatted-keys (which-key/get-formatted-key-bindings
+                               buf prefix-keys))
+              ;; populate target buffer
+              (popup-act-dim (which-key/populate-buffer
+                              (key-description prefix-keys)
+                              formatted-keys (window-width))))
+         ;; show buffer
+         (which-key/show-popup popup-act-dim)))))
+ ;; Timers
  
+ (defun which-key/start-open-timer ()
+   "Activate idle timer."
+   (which-key/stop-open-timer) ; start over
+   (setq which-key--open-timer
+         (run-with-idle-timer which-key-idle-delay t 'which-key/update)))
+ (defun which-key/stop-open-timer ()
+   "Deactivate idle timer."
+   (when which-key--open-timer (cancel-timer which-key--open-timer)))
  (provide 'which-key)
  
  ;;; which-key.el ends here